home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1997
/
MacHack 1997.toast
/
Hacks
/
Hacks ’96
/
PredatorPrey
/
Cursors.c
< prev
next >
Wrap
Text File
|
1996-06-22
|
8KB
|
254 lines
/* © 1988-91, Bowers Development Corp. */
/* Cursors.c */
#include <Types.h>
#include <Quickdraw.h>
#include <Controls.h>
#include <Dialogs.h>
#include <Events.h>
#include <Lists.h>
#include <Menus.h>
#include <Resources.h>
#include "Globals.h" /* for inBackground, curEvent, curWindow, cur, etc. */
#include "Cursors.h"
#include <ToolUtils.h> /* for GetCursor, HiWord */
#pragma segment Cursors
RgnHandle cursorRgn;
CursHandle watch;
#define kSpinTicks 15 /*1/4 of a second*/
#define topLeft(r) (((Point *) &(r))[0])
#define botRight(r) (((Point *) &(r))[1])
typedef struct
{
struct
{
unsigned short isColor : 1; /*TRUE ===> using color cursors (high bit)*/
unsigned short count : 15; /*# of cursors or “frames” in the cursor list (0-15th bits)*/
} info;
short frame; /*cursor list index of the next cursor frame (0-based)*/
CursHandle hCursors [1]; /*Variable-sized list of cursor handles (0-based index)*/
} AnimCursRec, *AnimCursPtr, **AnimCursHnd;
static CursHandle iBeam;
static AnimCursHnd shAnimCurs; /*=> Animated cursor list*/
static long sLastTick; /*TickCount of last SetCursor call*/
/*----------*/
void LoadCursors ()
{
watch = GetCursor (watchCursor);
iBeam = GetCursor (iBeamCursor);
cursorRgn = NewRgn ();
InitCursor ();
} /*LoadCursors*/
/*----------*/
static void GlobalRectRgn (RgnHandle destRegion,
Rect sourceRect);
static void GlobalRectRgn (RgnHandle destRegion,
Rect sourceRect)
{
LocalToGlobal (&topLeft (sourceRect));
LocalToGlobal (&botRight (sourceRect));
RectRgn (destRegion, &sourceRect);
} /*GlobalRectRgn*/
/*----------*/
void ShapeCursor ()
{
WindowPtr front;
WindowPeek frontPeek;
Point mousePoint;
RgnHandle arrowRgn;
RgnHandle iBeamRgn;
Rect textRect;
RgnHandle contentRgn;
RgnHandle scrollBarRgn;
Rect scrollBarRect;
front = FrontWindow ();
frontPeek = (WindowPeek) front;
if (inBackground) {
/*let foreground set cursor*/
} else if ((front != NULL) && (frontPeek->windowKind < 0)) {
/*let da set its own cursor*/
} else {
arrowRgn = NewRgn ();
iBeamRgn = NewRgn ();
contentRgn = NewRgn ();
scrollBarRgn = NewRgn ();
RectRgn (arrowRgn, &qd.screenBits.bounds);
mousePoint = curEvent.where;
if (front == NULL) {
/*arrow*/
} else if (front == curWindow) {
SetPort (curWindow); /*for local-to-global*/
GlobalRectRgn (contentRgn, qd.thePort->portRect);
if (cur->vScroll != NULL) {
scrollBarRect = (**(cur->vScroll)).contrlRect;
GlobalRectRgn (scrollBarRgn, scrollBarRect);
DiffRgn (contentRgn, scrollBarRgn, contentRgn);
}
if (cur->hScroll != NULL) {
scrollBarRect = (**(cur->hScroll)).contrlRect;
GlobalRectRgn (scrollBarRgn, scrollBarRect);
DiffRgn (contentRgn, scrollBarRgn, contentRgn);
}
if (cur->text != NULL) {
textRect = (**(cur->text)).viewRect;
GlobalRectRgn (iBeamRgn, textRect);
SectRgn (iBeamRgn, contentRgn, iBeamRgn);
}
DiffRgn (arrowRgn, iBeamRgn, arrowRgn);
}
if (PtInRgn (mousePoint, iBeamRgn)) {
SetCursor (&(**iBeam));
CopyRgn (iBeamRgn, cursorRgn);
} else {
SetCursor (&qd.arrow);
CopyRgn (arrowRgn, cursorRgn);
}
DisposeRgn (arrowRgn);
DisposeRgn (iBeamRgn);
DisposeRgn (contentRgn);
DisposeRgn (scrollBarRgn);
}
} /*ShapeCursor*/
/*----------*/
/* This procedure sets up this unit so that later calls to SpinCursor will spin */
/* the 'acur' resource with id aCurID. You MUST call StartBusyCursor before calling */
/* SpinCursor, SpinBackwards, or StopBusyCursor. */
/*----------*/
void StartBusyCursor (short aCurID)
{
short cursID; /*==> One cursor's rsrc id in shAnimCurs*/
CursHandle hCurs; /*==> One cursor in shAnimCurs*/
unsigned short i; /*index into animated cursor list*/
Boolean isColor; /*TRUE if cursor list has color cursors, FALSE otherwise*/
shAnimCurs = (AnimCursHnd) GetResource ('acur', aCurID);
if (shAnimCurs != NULL) {
HNoPurge ((Handle) shAnimCurs); /*We need to make shAnimCurs non-purgeable for its life span*/
isColor = (**shAnimCurs).info.isColor;
/* The cursor list is a list of CursHandles, but in the resource file the cursor list is a list */
/* of resource IDs in the upper 16 bits of the CursHandles. */
for (i = 0; i < (**shAnimCurs).info.count; i++) {
cursID = (short) HiWord ( (long) (**shAnimCurs).hCursors [i]);
if (isColor) {
hCurs = (CursHandle) GetCCursor (cursID);
} else {
hCurs = GetCursor (cursID);
}
(**shAnimCurs).hCursors [i] = hCurs; /*Replace the resource IDs with CursHandles*/
/* If the cursor is a non-color cursor ('curS' resource); make it non-purgeable. GetCColor */
/* returns copies of the 'crsr' resources so they are already non-purgeable. */
if ((!isColor) && (hCurs != NULL)) {
HNoPurge ((Handle) hCurs);
}
} /*for*/
} /*otherwise, shAnimCurs == NULL, resource not found*/
sLastTick = 0;
} /*StartBusyCursor*/
/*----------*/
/* This private procedure spins the cursor by frameInc if more than kSpinTicks ticks have gone
| by since it last changed the cursor.
*/
/*----------*/
static void SpinFrame(short frameInc);
static void SpinFrame(short frameInc)
{
short count; /*count of animated cursors*/
short frameNum; /*index into animated cursor list*/
CursHandle hCurs; /*==> One cursor in shAnimCurs*/
long ticks;
if (shAnimCurs != NULL) {
ticks = TickCount ();
if ((ticks - sLastTick) > kSpinTicks) {
count = (**shAnimCurs).info.count;
/* Enough time has elapsed since last cursor change, so change the cursor, bump the */
/* frame count and note the ticks for next time. */
frameNum = (**shAnimCurs).frame % count;
hCurs = (**shAnimCurs).hCursors [frameNum];
if (hCurs != NULL) {
if ((**shAnimCurs).info.isColor) {
SetCCursor ((CCrsrHandle) hCurs);
} else {
HLock ((Handle) hCurs);
SetCursor (&(**hCurs));
HUnlock ((Handle) hCurs);
}
} /*otherwise, hCurs == NULL*/
(**shAnimCurs).frame = (frameNum + count + frameInc) % count;
/* if (frameInc < 0,) frameNum + frameInc */
/* may be < 0, so (frameNum + frameInc) % count */
/* would also be < 0. */
/* Using frameNum + count + frameInc makes this */
/* less likely to happen. */
sLastTick = ticks;
} /*otherwise, not enough time has elapsed to change the cursor*/
} /*otherwise, shAnimCurs == NULL*/
} /*SpinFrame*/
/*----------*/
/* This procedure should be called as often as possible when the cursor is supposed to spin. */
/* It will spin the cursor forward one frame if more than kSpinTicks ticks have gone by since */
/* it last changed the cursor. */
/*----------*/
void SpinCursor (void)
{
SpinFrame (1 /*frameInc*/);
} /*SpinCursor*/
/*----------*/
/* This procedure should be called as often as possible when the cursor is supposed to spin. */
/* It will spin the cursor backward one frame if more than kSpinTicks ticks have gone by since */
/* it last changed the cursor. */
/*----------*/
void SpinBackwards (void)
{
SpinFrame (-1 /*frameInc*/);
} /*SpinBackwards*/
/*----------*/
/* This procedure does the opposite of StartBusyCursor, that is, it disposes of the spinning */
/* cursor allocated by StartBusyCursor, and sets the cursor to the standard arrow. */
/*----------*/
void StopBusyCursor (void)
{ CursHandle hCurs; /*==> One cursor in shAnimCurs*/
unsigned short i; /*index into animated cursor list*/
Boolean isColor; /*TRUE if cursor list has color cursors, FALSE otherwise*/
if (shAnimCurs != NULL) {
/*Dispose shAnimCurs's handles*/
isColor = (**shAnimCurs).info.isColor;
for (i = 0; i < (**shAnimCurs).info.count; i++) {
hCurs = (**shAnimCurs).hCursors [i];
if (hCurs != NULL) {
if (isColor) {
DisposCCursor ((CCrsrHandle) hCurs);
} else {
HPurge ((Handle) hCurs);
}
} /*otherwise, hCurs == NULL*/
} /*otherwise, not enough time has elapsed to change the cursor*/
ReleaseResource ((Handle) shAnimCurs);
shAnimCurs = NULL;
sLastTick = 0;
} /*otherwise, shAnimCurs == NULL*/
InitCursor ();
} /*StopBusyCursor*/